package com.pmcc.core.config.security;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    private final Log logger = LogFactory.getLog(this.getClass());

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.header}")
    private String tokenHeader;

    @Override
    @ResponseBody
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {

//        String authToken = request.getHeader(this.tokenHeader);
//        String username = jwtTokenUtil.getUsernameFromToken(authToken);
//
//        logger.info("checking authentication für user " + username);
//        if( StringUtils.isNotEmpty(username) && SecurityContextHolder.getContext().getAuthentication() == null){
//            // It is not compelling necessary to load the use details from the database. You could also store the information
//            // in the token and read it from it. It's up to you ;)
//            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
//
//            // For simple validation it is completely sufficient to just check the token integrity. You don't have to call
//            // the database compellingly. Again it's up to you ;)
//            if (jwtTokenUtil.validateToken(authToken, userDetails)) {
//                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
//                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//                logger.info("authenticated user " + username + ", setting security context");
//                SecurityContextHolder.getContext().setAuthentication(authentication);
//            }
//        }
//        chain.doFilter(request, response);
        // 静态文件
        boolean staticFlag = false;
        String staticUrl = ".html,.ico,.woff,.ttf,.css,.js,.png,.jpg,.jpeg,.gif,.woff,.woff2,.txt,.HTML,.ICO,.WOFF,.TTF,.CSS,.JS,.PNG,.JPG,.JPEG,.GIF,.WOFF,.WOFF2,.TXT,.svg,.SVG";
        for (int i = 0; i < staticUrl.split(",").length; i++) {
            staticFlag = request.getServletPath().endsWith(staticUrl.split(",")[i]);
            if (staticFlag) {
                break;
            }
        }
        if (staticFlag) {// true 不需要校验
            chain.doFilter(request, response);
            return;
        }

        //不需要 token 校验
        //String ignoreUrl = "/auth,/app/(.*),/download/(.*),/";
        boolean flag = true;
        /*for(int i=0;i<ignoreUrl.split(",").length;i++){
            flag = request.getServletPath().matches(ignoreUrl.split(",")[i]);
            if(flag){
                break;
            }
        }*/
        if(flag){
            chain.doFilter(request, response);
            return;
        }

        String authToken = request.getHeader(this.tokenHeader);
        String username = jwtTokenUtil.getUsernameFromToken(authToken);

        logger.info("checking authentication für user " + username);
        if (StringUtils.isEmpty(authToken) || StringUtils.isEmpty(username)) {
            logger.info("无用户信息");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        } else {
            if(SecurityContextHolder.getContext().getAuthentication() == null){
                // It is not compelling necessary to load the use details from the database. You could also store the information
                // in the token and read it from it. It's up to you ;)
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

                // For simple validation it is completely sufficient to just check the token integrity. You don't have to call
                // the database compellingly. Again it's up to you ;)
                if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    logger.info("authenticated user " + username + ", setting security context");
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                    chain.doFilter(request, response);
                }else {
                    logger.info("token 非法或超时");
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                }
            }else {
                chain.doFilter(request, response);
            }
        }
    }
}